import { FC, ReactElement, useEffect } from "react";
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
import { FontLoader } from "three/examples/jsm/loaders/FontLoader";
import { TextGeometry } from "three/examples/jsm/geometries/TextGeometry";
import ALFontJSON from "../assets/Alibaba PuHuiTi Light_Regular.json";
import DAT from "dat.gui";

interface IProps {}
const Try: FC<IProps> = (): ReactElement => {
  useEffect(() => {
    const canvas = document.getElementById("canvas") as HTMLCanvasElement;
    let camera: THREE.PerspectiveCamera,
      controls: OrbitControls,
      scene = new THREE.Scene(),
      renderer: THREE.WebGLRenderer;
    const gui = new DAT.GUI();
    gui.close();
    const textureLoader = new THREE.TextureLoader();
    const bg1 = require("../assets/b1.jpg");
    const bg2 = require("../assets/b2.jpg");

    const texture1 = textureLoader.load(bg1);
    const texture2 = textureLoader.load(bg2);
    const door1Texture = textureLoader.load(require("../assets/door1.jpg"));
    const caodi = textureLoader.load(require("../assets/caodi.jpg"));

    caodi.wrapS = THREE.RepeatWrapping;
    caodi.wrapT = THREE.RepeatWrapping;

    const clock = new THREE.Clock();
    const sun = new THREE.PointLight(0xdddddd, 1);
    init();
    animate();

    // addItem();
    addLights();
    // addPlane();
    // addFont();

    const halfPI = Math.PI / 2;

    function init() {
      scene.add(new THREE.AxesHelper(500));
      scene.background = new THREE.Color(0xcccccc);
      // 雾
      scene.fog = new THREE.FogExp2(0xcccccc, 0.002);

      renderer = new THREE.WebGLRenderer({ antialias: true, canvas });
      // 最多2倍像素
      renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
      renderer.setSize(window.innerWidth, window.innerHeight);
      //   document.body.appendChild(renderer.domElement);
      //允许阴影
      renderer.shadowMap.enabled = true;
      // renderer.shadowMap.type = THREE.PCFSoftShadowMap;
      camera = new THREE.PerspectiveCamera(
        60,
        window.innerWidth / window.innerHeight,
        1,
        1000
      );
      //设置摄像头的位置
      camera.position.set(0, 20, 20);

      // controls

      controls = new OrbitControls(camera, renderer.domElement);
      controls.listenToKeyEvents(window as any); // optional

      //controls.addEventListener( 'change', render ); // call this only in static scenes (i.e., if there is no animation loop)

      controls.enableDamping = true; // an animation loop is required when either damping or auto-rotation are enabled
      //   controls.dampingFactor = 0.5;//阻尼惯性 需要一直开update

      controls.screenSpacePanning = false;

      // controls.minDistance = 10;
      // controls.minZoom = 10;
      // controls.maxDistance = 500;
      //可旋转角度
      // controls.maxPolarAngle = Math.PI / 2.2;

      window.addEventListener("resize", onWindowResize);
    }

    for (let i = 0; i < 5; i++) {
      const w = Math.random() * 10 + 4;
      const h = House(w, w * 2);
      h.position.set(Math.random() * 100 - 50, 0, Math.random() * 100 - 50);
      h.rotateY(Math.random());
      scene.add(h);
    }

    function House(width: number = 5, length: number = 10) {
      /*
        记录该实例的组成元素 将每个元素的id和类型存入每个实例的自定义输入
        可以在用户点击任意属于该实例组成部分时控制其他部分
        例如:点击房盖 控制房门打开关闭
        */
      const house: any = {};
      const elements = [];
      const group = new THREE.Group();
      const material = new THREE.MeshLambertMaterial({
        map: texture1,
        side: THREE.DoubleSide,
      });
      texture2.repeat.set(2, 2);
      const material2 = new THREE.MeshLambertMaterial({
        map: texture2,
        side: THREE.DoubleSide,
      });
      const door1Mesh = new THREE.MeshLambertMaterial({
        map: door1Texture,
        side: THREE.DoubleSide,
      });

      //控制房子大小主要数据
      const floorProps = [width, length]; //width length
      const floor = new THREE.Mesh(
        new THREE.PlaneGeometry(...floorProps),
        material
      );
      floor.rotateX(halfPI);
      floor.rotateZ(halfPI);
      elements.push({ element: floor, type: "floor" });
      const sideProps = [floorProps[0], 4]; //width,height
      const leftSide = new THREE.Mesh(
        new THREE.PlaneGeometry(...sideProps),
        material
      );
      leftSide.position.set(-floorProps[1] / 2, sideProps[1] / 2, 0);
      leftSide.rotateY(halfPI);

      const rightSide = new THREE.Mesh(
        new THREE.PlaneGeometry(...sideProps),
        material
      );
      rightSide.position.set(floorProps[1] / 2, sideProps[1] / 2, 0);
      rightSide.rotateY(halfPI);
      elements.push(
        { element: leftSide, type: "leftSide" },
        { element: rightSide, type: "rightSide" }
      );
      const back = new THREE.Mesh(
        new THREE.PlaneGeometry(floorProps[1], sideProps[1]),
        material
      );
      back.position.set(0, sideProps[1] / 2, -floorProps[0] / 2);
      elements.push({ element: back, type: "back" });
      //前面墙
      const heartShape = new THREE.Shape();
      const pointX = floorProps[1] / 2;
      const pointY = sideProps[1] / 2;
      heartShape.moveTo(-pointX, -pointY);
      heartShape.lineTo(-pointX, pointY);
      heartShape.lineTo(pointX, pointY);
      heartShape.lineTo(pointX, -pointY);
      heartShape.lineTo(-pointX, -pointY);
      //开一个口 留门
      const holeX = pointX / 3;
      const holeY = pointY / 3;
      const windowHole = new THREE.Path();
      windowHole.moveTo(-holeX, holeY);
      windowHole.lineTo(0, holeY);
      windowHole.lineTo(0, -pointY);
      windowHole.lineTo(-holeX, -pointY);
      windowHole.lineTo(-holeX, holeY);
      heartShape.holes.push(windowHole);

      const frontGeometry = new THREE.ShapeGeometry(heartShape);
      const front = new THREE.Mesh(frontGeometry, material2);
      front.position.set(0, sideProps[1] / 2, floorProps[0] / 2);
      elements.push({ element: front, type: "front" });
      //门
      const box = new THREE.BoxGeometry(holeX, pointY + pointY / 3, 0.1);
      const door = new THREE.Mesh(box, door1Mesh);
      door.position.set(-holeX / 2, (pointY / 3) * 2, floorProps[0] / 2);
      elements.push({ element: door, type: "door" });
      //房盖
      const coverHeight = 2;
      const cover = new THREE.Mesh(
        new THREE.CylinderBufferGeometry(
          coverHeight,
          coverHeight,
          floorProps[1] + coverHeight,
          3
        ),
        material
      );
      cover.position.y = sideProps[1] + coverHeight / 2;
      cover.scale.x = floorProps[0] / 3;
      cover.rotateX(-halfPI);
      cover.rotateZ(halfPI);
      elements.push({ element: cover, type: "cover" });
      //生成信息
      for (const { element, type } of elements) {
        house[type] = element.id;
      }
      //每个元素记录所有相关信息 然后添加到group中
      for (const { element } of elements) {
        element.userData = { type: "house", house };
        group.add(element);
      }
      return group;
    }

    function addItem() {
      const material = new THREE.MeshPhongMaterial({
        color: 0xffffff,
        map: texture1,
      });

      for (let i = 0; i < 50; i++) {
        const h = Math.random() * 40 + 10;
        const geometry = new THREE.CylinderGeometry(10, 20, h, 4, 1);
        const mesh = new THREE.Mesh(geometry, material);
        mesh.position.x = Math.random() * 460 - 460 / 2;
        mesh.position.y = 0;
        mesh.position.z = Math.random() * 460 - 460 / 2;
        // mesh.updateMatrix();
        // mesh.matrixAutoUpdate = false;
        mesh.castShadow = true; //激活阴影
        scene.add(mesh);
      }
    }

    function addLights() {
      const dirLight1 = new THREE.DirectionalLight(0xdddddd, 1);
      dirLight1.position.set(1, 1, 1);
      scene.add(dirLight1);
      sun.position.set(100, 120, 5);
      sun.castShadow = true;
      sun.shadow.mapSize.width = 1024;
      sun.shadow.mapSize.height = 1024;
      sun.shadow.radius = 10;
      scene.add(sun);

      const dirLight2 = new THREE.DirectionalLight(0x002288);
      dirLight2.position.set(-1, -1, -1);
      scene.add(dirLight2);
      //背面的光
      const ambientLight = new THREE.AmbientLight(0x666666);
      scene.add(ambientLight);
    }

    //地面
    function addPlane() {
      const geometry = new THREE.PlaneGeometry(1000, 1000);
      const material = new THREE.MeshStandardMaterial({
        side: THREE.BackSide, //只有背面绘制 另一面不需要
        map: caodi,
      });
      const plane = new THREE.Mesh(geometry, material);
      geometry.rotateX(Math.PI / 2);
      //接收阴影
      plane.receiveShadow = true;
      plane.castShadow = true;
      geometry.center();
      scene.add(plane);
    }

    //文字
    function addFont() {
      const fontLoad = new FontLoader();

      const font = fontLoad.parse(ALFontJSON);
      if (font) {
        const geometry = new TextGeometry("抗美援朝，保家卫国", {
          font,
          size: 30,
          height: 5,
          curveSegments: 8,
          bevelEnabled: true,
          bevelThickness: 1.3,
          bevelSize: 0.5,
          bevelOffset: 0,
          bevelSegments: 5,
        });

        // const material = new THREE.MeshBasicMaterial({
        const material = new THREE.MeshPhongMaterial({
          map: texture1,
          //   normalMap: texture2,
          //   wireframe: true,
        });
        const text = new THREE.Mesh(geometry, material);
        text.translateY(30);
        geometry.center();
        text.position.z = -300;
        scene.add(text);
      }
    }

    function onWindowResize() {
      camera.aspect = window.innerWidth / window.innerHeight;
      camera.updateProjectionMatrix();

      renderer.setSize(window.innerWidth, window.innerHeight);
    }

    function animate() {
      requestAnimationFrame(animate);
      render();
      sunRun();
    }

    function render() {
      renderer.render(scene, camera);
    }
    //太阳运动
    function sunRun() {
      const elapsedTime = clock.getElapsedTime();
      sun.position.x = Math.cos(elapsedTime / 10) * 200;
    }

    //点击监听
    canvas.addEventListener("click", event => {
      event.preventDefault();
      const intersects = getIntersects(event);
      // 获取选中最近的 Mesh 对象
      if (intersects.length && intersects[0].object instanceof THREE.Mesh) {
        const selectObject = intersects[0].object;
        if (selectObject.userData.type === "house") {
          handleHouseClick(selectObject.userData.house);
        }
        // changeMaterial(selectObject);
      }
    });

    function getIntersects(event: MouseEvent) {
      // 声明 raycaster 和 mouse 变量
      var raycaster = new THREE.Raycaster();
      var mouse = new THREE.Vector2();

      // 通过鼠标点击位置,计算出 raycaster 所需点的位置,以屏幕为中心点,范围 -1 到 1
      mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
      mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;

      //通过鼠标点击的位置(二维坐标)和当前相机的矩阵计算出射线位置
      raycaster.setFromCamera(mouse, camera);

      // 获取与射线相交的对象数组，其中的元素按照距离排序，越近的越靠前
      var intersects = raycaster.intersectObjects(scene.children);

      //返回选中的对象
      return intersects;
    }

    function handleHouseClick(house: any) {
      const mash = scene.getObjectByProperty("id", house.door);
      if (mash) {
        console.log("door:", mash);
        mash.position.x *= -1;
      }
    }
  }, []);

  return <canvas id='canvas'></canvas>;
};

export default Try;
